﻿// ———————————————————————–
// <copyright file="DEPostService.svc.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// DEPostService.svc.cs - "Parses DEs And Puts Them In Appropriate ValueLists"
// Project: "ICNETSOA"- "ICNETREST"
//
// Language:    C#, .NET 4.0
// Platform:    Windows 7, VS 2010
// Author:      Don McGarry The MITRE Corporation
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)

using Amazon.SQS;
using Amazon.SQS.Model;
using EDXLSharp.EDXLDELib;
using ICNETServices;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Xml.Linq;

// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace ICNETREST
{

  /// <summary>
  /// Methods to parse a DE and send it to be processed.
  /// </summary>
  [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
  public class DEPostService : IDEPost
  {
    // Create a logger for use in this class
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Handles a post of plain Text instead of xml, to allow cross domain javascript to work.
    /// Then Figures out the type of content object is in the DE, and puts it in the appropriate database. 
    /// </summary>
    /// <param name="input">The DE Object thta will be parsed</param>
    /// <returns>The DE Object as it was passed in.</returns>
    [WebInvoke(UriTemplate = "crossdomain")]
    public XElement CrossDomainCreate(Stream input)
    {
      //WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
      string senderIP = (OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty).Address;
      string senderURI = OperationContext.Current.IncomingMessageHeaders.To.OriginalString;

      StreamReader sr = new StreamReader(input);
      string body = sr.ReadToEnd(); sr.Dispose();

      XElement xml = XElement.Parse(body);

      if (xml == null)
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest;
        WebOperationContext.Current.OutgoingResponse.StatusDescription = "Post Failed. Provided XML is missing.";
        return new XElement("Failure");
      }
      else if (!xml.HasElements)
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest;
        WebOperationContext.Current.OutgoingResponse.StatusDescription = "Post Failed. Provided XML is incomplete.";
        return new XElement("Failure");
      }

      XElement results = AddToDatabase(senderIP, senderURI, xml);
      return results;
    }


    /// <summary>
    /// Test the cross domain posting gateway
    /// </summary>
    /// <param name="input">The DE Object thta will be parsed</param>
    /// <returns>The DE Object as it was passed in.</returns>
    [WebInvoke(UriTemplate = "crossdomaintest")]
    public XElement CrossDomainTest(Stream input)
    {
      StreamReader sr = new StreamReader(input);
      string body = sr.ReadToEnd(); sr.Dispose();

      XElement xml = XElement.Parse(body);

      return xml;
    }

    /// <summary>
    /// Test the cross domain posting gateway, with a manually built header
    /// </summary>
    /// <param name="input">The DE Object thta will be parsed</param>
    /// <returns>The DE Object as it was passed in.</returns>
    [WebInvoke(UriTemplate = "crossdomaintest2")]
    public XElement CrossDomainTest2(Stream input)
    {
      WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
      StreamReader sr = new StreamReader(input);
      string body = sr.ReadToEnd(); sr.Dispose();

      XElement xml = XElement.Parse(body);

      return xml;
    }


    /// <summary>
    /// Figures out the type of content object is in the DE, and puts it in the appropriate database. 
    /// </summary>
    /// <param name="xe">The DE Object thta will be parsed</param>
    /// <returns>The DE Object as it was passed in.</returns>
    [WebInvoke(UriTemplate = "", Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
    public XElement Create(XElement xe)
    {
      string senderIP = (OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty).Address;
      string senderURI = OperationContext.Current.IncomingMessageHeaders.To.OriginalString;
      log.Info("Got Message from " + senderIP + " " + senderURI);

      if (xe == null)
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest;
        WebOperationContext.Current.OutgoingResponse.StatusDescription = "Post Failed. Provided XML is missing.";
        log.Info("XE is null");
        return new XElement("Failure");
      }
      else if (!xe.HasElements)
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest;
        WebOperationContext.Current.OutgoingResponse.StatusDescription = "Post Failed. Provided XML is incomplete.";
        log.Info("Post Failed. Provided XML is incomplete.");
        return new XElement("Failure");
      }
      else
      {
        try
        {
          return AddToDatabase(senderIP, senderURI, xe);
        }
        catch (Exception ex)
        {
          WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError;
          WebOperationContext.Current.OutgoingResponse.StatusDescription = "Post Failed. Internal Error:" + ex.Message;
          return new XElement("Failure", ex.Message);
        }
      }
    }
    [WebInvoke(UriTemplate = "", Method = "OPTIONS")]
    public string Cors()
    {
      return "great success";
    }


    private XElement AddToDatabase(string senderIP, string senderURI, XElement xe)
    {
      string s = xe.ToString(SaveOptions.None);
      EDXLDE distributionElement = new EDXLDE(s);
      log.Info(s);
      //Removing the History write here as it will be handled on the backend.  
      //int historyId = History.AddReceivedMessageToDB(distributionElement.DistributionID, distributionElement.SenderID, distributionElement.DateTimeSent.ToLocalTime(), senderIP, senderURI, xe);

      // remove SenderRoles that are marked as 'internal', they are potentially harmful to the normal message flow - 7/3/14 - this is no longer needed as we won't be adding the internal
      //roles in for SQS
      AmazonSQSConfig amazonSQSConfig = new AmazonSQSConfig();

      amazonSQSConfig.ServiceURL = AWSConstants.SQSServiceURL;
    
      AmazonSQSClient amazonSQSClient = new AmazonSQSClient(amazonSQSConfig);
      List<string> sqsqueues = new List<string>();
      sqsqueues.Add(AWSConstants.DEProcessingQueueUrl);
      sqsqueues.Add(AWSConstants.ContentProcessingQueueUrl);
      sqsqueues.Add(AWSConstants.HistoryProcessingQueueUrl);
      sqsqueues.Add(AWSConstants.FederationProcessingQueueUrl);

      foreach (string queue in sqsqueues)
      {
        SendMessageResponse resp = amazonSQSClient.SendMessage(queue, s);
        if (resp.HttpStatusCode == System.Net.HttpStatusCode.OK)
        {
          log.Info("Message sent to SQS Queue: " + queue);
        }
        else
        {
          log.Error("SQS Error for queue: " + queue + resp.HttpStatusCode.ToString());
        }
      }
      //This will be handled by logging
      //History.AddServiceStatusToDB(distributionElement.DistributionID, distributionElement.SenderID, distributionElement.DateTimeSent.ToLocalTime(), 
      // "DEPostService", History.ServiceStatusEnum.Success, DateTime.Now, "");
      return xe;
    }

  }
}
